//import ReconnectingWebSocket from 'reconnecting-websocket';
import { browser } from "webextension-polyfill-ts";

import {
    lineGroup,
    lineNodes,
    closeProxy,
    createProxy,
    notifications,
    payNotice,
    checkCreateProxy,
    getvpnStore,
    setvpnStore,
    errorLog,
    updateNotifications,
} from "./utils";

import { UDPCmd } from "../Popup/enum";

import {
    SubVersion,
    MainVersion,
    Platform,
    wsURL,
    PatchUpdate,
    ForedUpdate,
} from "../config";

let ws: any = null;
let connected = false;
let timerbeat: any = null;
let promisePool: any = {};
let timerConnent: any = null;
let timerSetProxy: any = null;

const cmdFilters = [3, 29, 26];
export function createWebsocket() {
    ws = new WebSocket(wsURL);

    ws.addEventListener("open", () => {
        //连接上后，开始发送心跳
        connected = true;
        headerbeat();
        login().then(() => {
            clearTimeout(timerSetProxy);
            timerSetProxy = setTimeout(() => {
                initProxy();
            }, 500);
        });
        //登录以后重新设置代理
    });

    ws.addEventListener("message", async (e: any) => {
        //res.data

        try {
            const data = JSON.parse(e.data);
            if (cmdFilters.includes(data.Cmd)) {
                return;
            }
            if (data.Cmd === 32) {
                payNotice(data.Body);
                return;
            }

            if (data.Cmd === 2) {
                await setvpnStore({ isLogin: false, vip: false });
                notifications(data.Body.Reason || "websocket被服务器断开");
                return;
            }

            //vip到期通知
            if (data.Cmd === 23) {
                //data.Body
                setvpnStore(
                    {
                        userInfo: {
                            Vip: data.Body.IsVip,
                            VipTime: data.Body.VipTime,
                            BoundDay: data.Body.BoundDay,
                        },
                        vip: data.Body.IsVip,
                    },
                    ["userInfo"]
                );
                return;
            }
            //当线路普通变成VIP时 发送该通知
            if (data.Cmd === 30) {
                const vpnStore = await getvpnStore();
                const { vip } = vpnStore;
                if (!vip) {
                    //更新当前的currentLine
                    await onNodesChanged();
                    await closeProxy();
                    notifications(
                        data.Body.ErrMsg ||
                            "您当前连接的节点已变更为VIP节点，继续使用需要VIP身份！"
                    );
                }

                return;
            }

            //节点列表变化通知
            if (data.Cmd === 20) {
                onNodesChanged();
                return;
            }
            //商品列表变化通知
            if (data.Cmd === 28) {
                onShopsChanged();
                return;
            }

            browser.storage.local.set({ [UDPCmd[data.Cmd]]: data.Body });
            //过滤心跳数据
            promisePool[data.MessageID].resove(data);
            delete promisePool[data.MessageID];
            return;
        } catch (e) {
            return errorLog(e);
        }
    });

    ws.addEventListener("close", () => {
        connected = false;
        reconnection();
    });

    ws.addEventListener("error", (e: any) => {
        console.log(e);
    });
}

export function reconnection() {
    clearTimeout(timerConnent);
    timerConnent = setTimeout(() => {
        ws.close();
        ws = null;

        createWebsocket();
    }, 5000);
}

function headerbeat() {
    if (connected) {
        clearInterval(timerbeat);
        timerbeat = setInterval(() => {
            ws.send(
                JSON.stringify({
                    ClientIdent: localStorage.ClientIdent,
                    Cmd: 3,
                    TimeStamp: new Date().getTime(),
                    BodyData: null,
                })
            );
        }, 30000);
    }
}

async function onNodesChanged() {
    return setvpnStore({
        nodesChanged: true,
    });
}

async function onShopsChanged() {
    return setvpnStore({
        shopChanged: true,
    });
}

async function login() {
    try {
        const result = await browser.storage.local.get([
            "LoginResult",
            "vpnStore",
        ]);
        if (result.vpnStore?.isLogin) {
            return regLogin(result.LoginResult);
        } else {
            return gusetLogin(result.LoginResult);
        }
    } catch (e: any) {
        return errorLog(e);
    }
}

async function gusetLogin(LoginResult: any) {
    try {
        let gusetLogin = {
            Cmd: 8,
            Body: {
                ClientIdent: localStorage.ClientIdent,
                Email: "",
                VerifyCode: "",
                Session: "",
                OsType: "IE",
                Platform: Platform(),
                MainVersion: MainVersion,
                SubVersion: SubVersion,
            },
        };
        const result: any = await send(gusetLogin);
        if (result.Code === 1) {
            updateNotifications(ForedUpdate, result.Body.UpdateURL);
            return Promise.reject(ForedUpdate);
        } else if (result.Code === 2) {
            updateNotifications(PatchUpdate, result.Body.UpdateURL);
        }
        await GetShops(result.Body.ShopListHash, LoginResult?.ShopListHash);
        return setvpnStore({ isLogin: false, vip: false });
    } catch (e) {
        return errorLog(e);
    }
}

async function regLogin(LoginResult: any) {
    try {
        let regLogin = {
            Cmd: 8,
            Body: {
                ClientIdent: localStorage.ClientIdent,
                Email: "",
                VerifyCode: "",
                Session: LoginResult.LoginSession,
                OsType: "IE",
                Platform: Platform(),
                MainVersion: MainVersion,
                SubVersion: SubVersion,
            },
        };

        const result: any = await send(regLogin);

        if (result.Code === 1) {
            updateNotifications(ForedUpdate, result.Body.UpdateURL);
            return Promise.reject(ForedUpdate);
        }

        if (result.Code === 0 || result.Code === 2) {
            if (result.Code === 2) {
                updateNotifications(PatchUpdate, result.Body.UpdateURL);
            }
            await setvpnStore({
                isLogin: true,
                vip: result.Body.Vip,
                userInfo: result.Body,
            });

            return GetShops(
                result.Body.ShopListHash,
                LoginResult?.ShopListHash
            );
        } else {
            return gusetLogin(LoginResult);
        }
    } catch (e) {
        return errorLog(e);
    }
}

export async function GetShops(newValue: string, oldValue: string) {
    try {
        if (newValue !== oldValue) {
            const ShopsResult: any = await send({ Cmd: 13, Body: {} });
            return setvpnStore({
                shopList: ShopsResult.Body.ShopList || [],
                shopChanged: false,
            });
        }
    } catch (e) {
        return errorLog(e);
    }
}

export function send(data: any) {
    return new Promise((resove) => {
        if (connected) {
            const { Cmd, Body } = data;
            ws.send(
                JSON.stringify({
                    ClientIdent: localStorage.ClientIdent,
                    Cmd: Cmd,
                    TimeStamp: new Date().getTime(),
                    BodyData: JSON.stringify(Body),
                })
            );
            promisePool[Cmd] = { resove };
        } else {
            throw new Error("websockt没有连接");
        }
    });
}

export async function initProxy() {
    try {
        const NodeList: any = await send({ Cmd: 11, Body: null });
        if (NodeList.Body.NodeList) {
            const vpnStore = await getvpnStore();
            const { currentLine, vip, connected, isLogin } = vpnStore;
            const nodeList = lineNodes(NodeList.Body.NodeList);
            let currentNode: any = currentLine;
            if (currentLine && currentLine.NodeName) {
                const node: any = nodeList.find(
                    (node: any) => node.Id === currentLine.Id
                );
                currentNode = node ? node : currentLine;
            } else {
                const line = nodeList.find((item: any) => !item.Vip);
                if (vip) {
                    const currentLine = nodeList.find((item: any) => item.Vip);
                    if (currentLine) {
                        currentNode = currentLine;
                    } else {
                        currentNode = line ? line : {};
                    }
                } else {
                    currentNode = line ? line : {};
                }
            }
            await setvpnStore({
                lineData: lineGroup(NodeList.Body.NodeList),
                nodesChanged: false,
                currentLine: currentNode,
            });
            if (checkCreateProxy(currentNode, vip, isLogin, connected)) {
                return await createProxy(currentNode);
            } else {
                return await closeProxy(false);
            }
        } else {
            const vpnStore = await getvpnStore();
            const { currentLine, connected } = vpnStore;
            let currentNode = {};
            if (currentLine && currentLine.NodeName) {
                currentNode = currentLine;
            }
            if (connected) {
                await closeProxy(false);
                return setvpnStore({
                    lineData: [],
                    nodesChanged: false,
                    currentLine: currentNode,
                    connected: false,
                });
            } else {
                return setvpnStore({
                    lineData: [],
                    nodesChanged: false,
                    currentLine: currentNode,
                });
            }
        }
    } catch (e) {
        return errorLog(e);
    }
}
